home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkFrame.c < prev    next >
C/C++ Source or Header  |  1995-06-04  |  25KB  |  784 lines

  1. /* 
  2.  * tkFrame.c --
  3.  *
  4.  *    This module implements "frame"  and "toplevel" widgets for
  5.  *    the Tk toolkit.  Frames are windows with a background color
  6.  *    and possibly a 3-D effect, but not much else in the way of
  7.  *    attributes.
  8.  *
  9.  * Copyright (c) 1990-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  */
  15.  
  16. static char sccsid[] = "@(#) tkFrame.c 1.59 95/06/04 14:08:47";
  17.  
  18. #include "default.h"
  19. #include "tkPort.h"
  20. #include "tkInt.h"
  21.  
  22. /*
  23.  * A data structure of the following type is kept for each
  24.  * frame that currently exists for this process:
  25.  */
  26.  
  27. typedef struct {
  28.     Tk_Window tkwin;        /* Window that embodies the frame.  NULL
  29.                  * means that the window has been destroyed
  30.                  * but the data structures haven't yet been
  31.                  * cleaned up. */
  32.     Display *display;        /* Display containing widget.  Used, among
  33.                  * other things, so that resources can be
  34.                  * freed even after tkwin has gone away. */
  35.     Tcl_Interp *interp;        /* Interpreter associated with widget.  Used
  36.                  * to delete widget command. */
  37.     Tcl_Command widgetCmd;    /* Token for frame's widget command. */
  38.     char *className;        /* Class name for widget (from configuration
  39.                  * option).  Malloc-ed. */
  40.     int mask;            /* Either FRAME or TOPLEVEL;  used to select
  41.                  * which configuration options are valid for
  42.                  * widget. */
  43.     char *screenName;        /* Screen on which widget is created.  Non-null
  44.                  * only for top-levels.  Malloc-ed, may be
  45.                  * NULL. */
  46.     char *visualName;        /* Textual description of visual for window,
  47.                  * from -visual option.  Malloc-ed, may be
  48.                  * NULL. */
  49.     char *colormapName;        /* Textual description of colormap for window,
  50.                  * from -colormap option.  Malloc-ed, may be
  51.                  * NULL. */
  52.     Colormap colormap;        /* If not None, identifies a colormap
  53.                  * allocated for this window, which must be
  54.                  * freed when the window is deleted. */
  55.     Tk_3DBorder border;        /* Structure used to draw 3-D border and
  56.                  * background.  NULL means no background
  57.                  * or border. */
  58.     int borderWidth;        /* Width of 3-D border (if any). */
  59.     int relief;            /* 3-d effect: TK_RELIEF_RAISED etc. */
  60.     int highlightWidth;        /* Width in pixels of highlight to draw
  61.                  * around widget when it has the focus.
  62.                  * 0 means don't draw a highlight. */
  63.     XColor *highlightBgColorPtr;
  64.                 /* Color for drawing traversal highlight
  65.                  * area when highlight is off. */
  66.     XColor *highlightColorPtr;    /* Color for drawing traversal highlight. */
  67.     int width;            /* Width to request for window.  <= 0 means
  68.                  * don't request any size. */
  69.     int height;            /* Height to request for window.  <= 0 means
  70.                  * don't request any size. */
  71.     Cursor cursor;        /* Current cursor for window, or None. */
  72.     char *takeFocus;        /* Value of -takefocus option;  not used in
  73.                  * the C code, but used by keyboard traversal
  74.                  * scripts.  Malloc'ed, but may be NULL. */
  75.     int flags;            /* Various flags;  see below for
  76.                  * definitions. */
  77. } Frame;
  78.  
  79. /*
  80.  * Flag bits for frames:
  81.  *
  82.  * REDRAW_PENDING:        Non-zero means a DoWhenIdle handler
  83.  *                has already been queued to redraw
  84.  *                this window.
  85.  * CLEAR_NEEDED;        Need to clear the window when redrawing.
  86.  * GOT_FOCUS:            Non-zero means this widget currently
  87.  *                has the input focus.
  88.  */
  89.  
  90. #define REDRAW_PENDING        1
  91. #define CLEAR_NEEDED        2
  92. #define GOT_FOCUS        4
  93.  
  94. /*
  95.  * The following flag bits are used so that there can be separate
  96.  * defaults for some configuration options for frames and toplevels.
  97.  */
  98.  
  99. #define FRAME        TK_CONFIG_USER_BIT
  100. #define TOPLEVEL    (TK_CONFIG_USER_BIT << 1)
  101. #define BOTH        (FRAME | TOPLEVEL)
  102.  
  103. static Tk_ConfigSpec configSpecs[] = {
  104.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  105.     DEF_FRAME_BG_COLOR, Tk_Offset(Frame, border),
  106.     BOTH|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK},
  107.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  108.     DEF_FRAME_BG_MONO, Tk_Offset(Frame, border),
  109.     BOTH|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK},
  110.     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
  111.     (char *) NULL, 0, BOTH},
  112.     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
  113.     (char *) NULL, 0, BOTH},
  114.     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  115.     DEF_FRAME_BORDER_WIDTH, Tk_Offset(Frame, borderWidth), BOTH},
  116.     {TK_CONFIG_STRING, "-class", "class", "Class",
  117.     DEF_FRAME_CLASS, Tk_Offset(Frame, className), FRAME},
  118.     {TK_CONFIG_STRING, "-class", "class", "Class",
  119.     DEF_TOPLEVEL_CLASS, Tk_Offset(Frame, className), TOPLEVEL},
  120.     {TK_CONFIG_STRING, "-colormap", "colormap", "Colormap",
  121.     DEF_FRAME_COLORMAP, Tk_Offset(Frame, colormapName),
  122.     BOTH|TK_CONFIG_NULL_OK},
  123.     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  124.     DEF_FRAME_CURSOR, Tk_Offset(Frame, cursor), BOTH|TK_CONFIG_NULL_OK},
  125.     {TK_CONFIG_PIXELS, "-height", "height", "Height",
  126.     DEF_FRAME_HEIGHT, Tk_Offset(Frame, height), BOTH},
  127.     {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
  128.     "HighlightBackground", DEF_FRAME_HIGHLIGHT_BG,
  129.     Tk_Offset(Frame, highlightBgColorPtr), BOTH},
  130.     {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  131.     DEF_FRAME_HIGHLIGHT, Tk_Offset(Frame, highlightColorPtr), BOTH},
  132.     {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
  133.     "HighlightThickness",
  134.     DEF_FRAME_HIGHLIGHT_WIDTH, Tk_Offset(Frame, highlightWidth), BOTH},
  135.     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
  136.     DEF_FRAME_RELIEF, Tk_Offset(Frame, relief), BOTH},
  137.     {TK_CONFIG_STRING, "-screen", "screen", "Screen",
  138.     DEF_TOPLEVEL_SCREEN, Tk_Offset(Frame, screenName),
  139.     TOPLEVEL|TK_CONFIG_NULL_OK},
  140.     {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
  141.     DEF_FRAME_TAKE_FOCUS, Tk_Offset(Frame, takeFocus),
  142.     BOTH|TK_CONFIG_NULL_OK},
  143.     {TK_CONFIG_STRING, "-visual", "visual", "Visual",
  144.     DEF_FRAME_VISUAL, Tk_Offset(Frame, visualName),
  145.     BOTH|TK_CONFIG_NULL_OK},
  146.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  147.     DEF_FRAME_WIDTH, Tk_Offset(Frame, width), BOTH},
  148.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  149.     (char *) NULL, 0, 0}
  150. };
  151.  
  152. /*
  153.  * Forward declarations for procedures defined later in this file:
  154.  */
  155.  
  156. static int        ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp,
  157.                 Frame *framePtr, int argc, char **argv,
  158.                 int flags));
  159. static void        DestroyFrame _ANSI_ARGS_((ClientData clientData));
  160. static void        DisplayFrame _ANSI_ARGS_((ClientData clientData));
  161. static void        FrameCmdDeletedProc _ANSI_ARGS_((
  162.                 ClientData clientData));
  163. static void        FrameEventProc _ANSI_ARGS_((ClientData clientData,
  164.                 XEvent *eventPtr));
  165. static int        FrameWidgetCmd _ANSI_ARGS_((ClientData clientData,
  166.                 Tcl_Interp *interp, int argc, char **argv));
  167. static void        MapFrame _ANSI_ARGS_((ClientData clientData));
  168.  
  169. /*
  170.  *--------------------------------------------------------------
  171.  *
  172.  * Tk_FrameCmd --
  173.  *
  174.  *    This procedure is invoked to process the "frame" and
  175.  *    "toplevel" Tcl commands.  See the user documentation for
  176.  *    details on what it does.
  177.  *
  178.  * Results:
  179.  *    A standard Tcl result.
  180.  *
  181.  * Side effects:
  182.  *    See the user documentation.
  183.  *
  184.  *--------------------------------------------------------------
  185.  */
  186.  
  187. int
  188. Tk_FrameCmd(clientData, interp, argc, argv)
  189.     ClientData clientData;    /* Main window associated with
  190.                  * interpreter. */
  191.     Tcl_Interp *interp;        /* Current interpreter. */
  192.     int argc;            /* Number of arguments. */
  193.     char **argv;        /* Argument strings. */
  194. {
  195.     Tk_Window tkwin = (Tk_Window) clientData;
  196.     Frame *framePtr;
  197.     Tk_Window new = NULL;
  198.     char *className, *screenName, *visualName, *colormapName, *arg;
  199.     int i, c, length, toplevel, depth;
  200.     Colormap colormap;
  201.     Visual *visual;
  202.     Display *display;
  203.  
  204.     if (argc < 2) {
  205.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  206.         argv[0], " pathName ?options?\"", (char *) NULL);
  207.     return TCL_ERROR;
  208.     }
  209.  
  210.     /*
  211.      * Pre-process the argument list.  Scan through it to find any
  212.      * "-class", "-screen", "-visual", and "-newcmap" options.  These
  213.      * arguments need to be processed specially, before the window
  214.      * is configured using the usual Tk mechanisms.
  215.      */
  216.  
  217.     toplevel = (argv[0][0] == 't');
  218.     className = colormapName = screenName = visualName = NULL;
  219.     for (i = 2; i < argc; i += 2) {
  220.     arg = argv[i];
  221.     length = strlen(arg);
  222.     if (length < 2) {
  223.         continue;
  224.     }
  225.     c = arg[1];
  226.     if ((c == 'c') && (strncmp(arg, "-class", strlen(arg)) == 0)
  227.         && (length >= 3)) {
  228.         className = argv[i+1];
  229.     } else if ((c == 'c')
  230.         && (strncmp(arg, "-colormap", strlen(arg)) == 0)) {
  231.         colormapName = argv[i+1];
  232.     } else if ((c == 's') && toplevel
  233.         && (strncmp(arg, "-screen", strlen(arg)) == 0)) {
  234.         screenName = argv[i+1];
  235.     } else if ((c == 'v')
  236.         && (strncmp(arg, "-visual", strlen(arg)) == 0)) {
  237.         visualName = argv[i+1];
  238.     }
  239.     }
  240.  
  241.     /*
  242.      * Create the window, and deal with the special options -classname,
  243.      * -colormap, -screenname, and -visual.  The order here is tricky,
  244.      * because we want to allow values for these options to come from
  245.      * the database, yet we can't do that until the window is created.
  246.      */
  247.  
  248.     if (screenName == NULL) {
  249.     screenName = (toplevel) ? "" : NULL;
  250.     }
  251.     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenName);
  252.     if (new == NULL) {
  253.     goto error;
  254.     }
  255.     if (className == NULL) {
  256.     className = Tk_GetOption(new, "class", "Class");
  257.     if (className == NULL) {
  258.         className = (toplevel) ? "Toplevel" : "Frame";
  259.     }
  260.     }
  261.     Tk_SetClass(new, className);
  262.     if (visualName == NULL) {
  263.     visualName = Tk_GetOption(new, "visual", "Visual");
  264.     }
  265.     if (colormapName == NULL) {
  266.     colormapName = Tk_GetOption(new, "colormap", "Colormap");
  267.     }
  268.     colormap = None;
  269.     if (visualName != NULL) {
  270.     visual = Tk_GetVisual(interp, new, visualName, &depth,
  271.         (colormapName == NULL) ? &colormap : (Colormap *) NULL);
  272.     if (visual == NULL) {
  273.         goto error;
  274.     }
  275.     Tk_SetWindowVisual(new, visual, depth, colormap);
  276.     }
  277.     if (colormapName != NULL) {
  278.     colormap = Tk_GetColormap(interp, new, colormapName);
  279.     if (colormap == None) {
  280.         goto error;
  281.     }
  282.     Tk_SetWindowColormap(new, colormap);
  283.     }
  284.  
  285.     /*
  286.      * Create the widget record, process configuration options, and
  287.      * create event handlers.  Then fill in a few additional fields
  288.      * in the widget record from the special options.
  289.      */
  290.  
  291.     display = Tk_Display(new);
  292.     framePtr = (Frame *) TkInitFrame(interp, new, toplevel, argc-2, argv+2);
  293.     if (framePtr == NULL) {
  294.     if (colormap != None) {
  295.         Tk_FreeColormap(display, colormap);
  296.     }
  297.     return TCL_ERROR;
  298.     }
  299.     framePtr->colormap = colormap;
  300.     return TCL_OK;
  301.  
  302.     error:
  303.     if (new != NULL) {
  304.     Tk_DestroyWindow(new);
  305.     }
  306.     return TCL_ERROR;
  307. }
  308.  
  309. /*
  310.  *----------------------------------------------------------------------
  311.  *
  312.  * TkInitFrame --
  313.  *
  314.  *    This procedure initializes a frame or toplevel widget.  It's
  315.  *    separate from Tk_FrameCmd so that it can be used for the
  316.  *    main window, which has already been created elsewhere.
  317.  *
  318.  * Results:
  319.  *    Returns NULL if an error occurred while initializing the
  320.  *    frame.  Otherwise returns a pointer to the frame's widget
  321.  *    record (for use by Tk_FrameCmd, if it was the caller).
  322.  *
  323.  * Side effects:
  324.  *    A widget record gets allocated, handlers get set up, etc..
  325.  *
  326.  *----------------------------------------------------------------------
  327.  */
  328.  
  329. char *
  330. TkInitFrame(interp, tkwin, toplevel, argc, argv)
  331.     Tcl_Interp *interp;            /* Interpreter associated with the
  332.                      * application. */
  333.     Tk_Window tkwin;            /* Window to use for frame or
  334.                      * top-level.   Caller must already
  335.                      * have set window's class. */
  336.     int toplevel;            /* Non-zero means that this is a
  337.                      * top-level window, 0 means it's a
  338.                      * frame. */
  339.     int argc;                /* Number of configuration arguments
  340.                      * (not including class command and
  341.                      * window name). */
  342.     char *argv[];            /* Configuration arguments. */
  343. {
  344.     register Frame *framePtr;
  345.  
  346.     framePtr = (Frame *) ckalloc(sizeof(Frame));
  347.     framePtr->tkwin = tkwin;
  348.     framePtr->display = Tk_Display(tkwin);
  349.     framePtr->interp = interp;
  350.     framePtr->widgetCmd = Tcl_CreateCommand(interp,
  351.         Tk_PathName(framePtr->tkwin), FrameWidgetCmd,
  352.         (ClientData) framePtr, FrameCmdDeletedProc);
  353.     framePtr->className = NULL;
  354.     framePtr->mask = (toplevel) ? TOPLEVEL : FRAME;
  355.     framePtr->screenName = NULL;
  356.     framePtr->visualName = NULL;
  357.     framePtr->colormapName = NULL;
  358.     framePtr->colormap = None;
  359.     framePtr->border = NULL;
  360.     framePtr->borderWidth = 0;
  361.     framePtr->relief = TK_RELIEF_FLAT;
  362.     framePtr->highlightWidth = 0;
  363.     framePtr->highlightBgColorPtr = NULL;
  364.     framePtr->highlightColorPtr = NULL;
  365.     framePtr->width = 0;
  366.     framePtr->height = 0;
  367.     framePtr->cursor = None;
  368.     framePtr->takeFocus = NULL;
  369.     framePtr->flags = 0;
  370.     Tk_CreateEventHandler(framePtr->tkwin,
  371.         ExposureMask|StructureNotifyMask|FocusChangeMask,
  372.         FrameEventProc, (ClientData) framePtr);
  373.     if (ConfigureFrame(interp, framePtr, argc, argv, 0) != TCL_OK) {
  374.     Tk_DestroyWindow(framePtr->tkwin);
  375.     return NULL;
  376.     }
  377.     if (toplevel) {
  378.     Tk_DoWhenIdle(MapFrame, (ClientData) framePtr);
  379.     }
  380.     interp->result = Tk_PathName(framePtr->tkwin);
  381.     return (char *) framePtr;
  382. }
  383.  
  384. /*
  385.  *--------------------------------------------------------------
  386.  *
  387.  * FrameWidgetCmd --
  388.  *
  389.  *    This procedure is invoked to process the Tcl command
  390.  *    that corresponds to a frame widget.  See the user
  391.  *    documentation for details on what it does.
  392.  *
  393.  * Results:
  394.  *    A standard Tcl result.
  395.  *
  396.  * Side effects:
  397.  *    See the user documentation.
  398.  *
  399.  *--------------------------------------------------------------
  400.  */
  401.  
  402. static int
  403. FrameWidgetCmd(clientData, interp, argc, argv)
  404.     ClientData clientData;    /* Information about frame widget. */
  405.     Tcl_Interp *interp;        /* Current interpreter. */
  406.     int argc;            /* Number of arguments. */
  407.     char **argv;        /* Argument strings. */
  408. {
  409.     register Frame *framePtr = (Frame *) clientData;
  410.     int result = TCL_OK;
  411.     size_t length;
  412.     int c, i;
  413.  
  414.     if (argc < 2) {
  415.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  416.         argv[0], " option ?arg arg ...?\"", (char *) NULL);
  417.     return TCL_ERROR;
  418.     }
  419.     Tk_Preserve((ClientData) framePtr);
  420.     c = argv[1][0];
  421.     length = strlen(argv[1]);
  422.     if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  423.         && (length >= 2)) {
  424.     if (argc != 3) {
  425.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  426.             argv[0], " cget option\"",
  427.             (char *) NULL);
  428.         result = TCL_ERROR;
  429.         goto done;
  430.     }
  431.     result = Tk_ConfigureValue(interp, framePtr->tkwin, configSpecs,
  432.         (char *) framePtr, argv[2], framePtr->mask);
  433.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  434.         && (length >= 2)) {
  435.     if (argc == 2) {
  436.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  437.             (char *) framePtr, (char *) NULL, framePtr->mask);
  438.     } else if (argc == 3) {
  439.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  440.             (char *) framePtr, argv[2], framePtr->mask);
  441.     } else {
  442.         /*
  443.          * Don't allow the options -class, -newcmap, -screen,
  444.          * or -visual to be changed.
  445.          */
  446.  
  447.         for (i = 2; i < argc; i++) {
  448.         length = strlen(argv[i]);
  449.         if (length < 2) {
  450.             continue;
  451.         }
  452.         c = argv[i][1];
  453.         if (((c == 'c') && (strncmp(argv[i], "-class", length) == 0)
  454.             && (length >= 2))
  455.             || ((c == 'c') && (framePtr->mask == TOPLEVEL)
  456.             && (strncmp(argv[i], "-colormap", length) == 0))
  457.             || ((c == 's') && (framePtr->mask == TOPLEVEL)
  458.             && (strncmp(argv[i], "-screen", length) == 0))
  459.             || ((c == 'v') && (framePtr->mask == TOPLEVEL)
  460.             && (strncmp(argv[i], "-visual", length) == 0))) {
  461.             Tcl_AppendResult(interp, "can't modify ", argv[i],
  462.                 " option after widget is created", (char *) NULL);
  463.             result = TCL_ERROR;
  464.             goto done;
  465.         }
  466.         }
  467.         result = ConfigureFrame(interp, framePtr, argc-2, argv+2,
  468.             TK_CONFIG_ARGV_ONLY);
  469.     }
  470.     } else {
  471.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  472.         "\":  must be cget or configure", (char *) NULL);
  473.     result = TCL_ERROR;
  474.     }
  475.  
  476.     done:
  477.     Tk_Release((ClientData) framePtr);
  478.     return result;
  479. }
  480.  
  481. /*
  482.  *----------------------------------------------------------------------
  483.  *
  484.  * DestroyFrame --
  485.  *
  486.  *    This procedure is invoked by Tk_EventuallyFree or Tk_Release
  487.  *    to clean up the internal structure of a frame at a safe time
  488.  *    (when no-one is using it anymore).
  489.  *
  490.  * Results:
  491.  *    None.
  492.  *
  493.  * Side effects:
  494.  *    Everything associated with the frame is freed up.
  495.  *
  496.  *----------------------------------------------------------------------
  497.  */
  498.  
  499. static void
  500. DestroyFrame(clientData)
  501.     ClientData clientData;    /* Info about frame widget. */
  502. {
  503.     register Frame *framePtr = (Frame *) clientData;
  504.  
  505.     Tk_FreeOptions(configSpecs, (char *) framePtr, framePtr->display,
  506.         framePtr->mask);
  507.     if (framePtr->colormap != None) {
  508.     Tk_FreeColormap(framePtr->display, framePtr->colormap);
  509.     }
  510.     ckfree((char *) framePtr);
  511. }
  512.  
  513. /*
  514.  *----------------------------------------------------------------------
  515.  *
  516.  * ConfigureFrame --
  517.  *
  518.  *    This procedure is called to process an argv/argc list, plus
  519.  *    the Tk option database, in order to configure (or
  520.  *    reconfigure) a frame widget.
  521.  *
  522.  * Results:
  523.  *    The return value is a standard Tcl result.  If TCL_ERROR is
  524.  *    returned, then interp->result contains an error message.
  525.  *
  526.  * Side effects:
  527.  *    Configuration information, such as text string, colors, font,
  528.  *    etc. get set for framePtr;  old resources get freed, if there
  529.  *    were any.
  530.  *
  531.  *----------------------------------------------------------------------
  532.  */
  533.  
  534. static int
  535. ConfigureFrame(interp, framePtr, argc, argv, flags)
  536.     Tcl_Interp *interp;        /* Used for error reporting. */
  537.     register Frame *framePtr;    /* Information about widget;  may or may
  538.                  * not already have values for some fields. */
  539.     int argc;            /* Number of valid entries in argv. */
  540.     char **argv;        /* Arguments. */
  541.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  542. {
  543.     if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs,
  544.         argc, argv, (char *) framePtr, flags | framePtr->mask) != TCL_OK) {
  545.     return TCL_ERROR;
  546.     }
  547.  
  548.     if (framePtr->border != NULL) {
  549.     Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border);
  550.     }
  551.     if (framePtr->highlightWidth < 0) {
  552.     framePtr->highlightWidth = 0;
  553.     }
  554.     Tk_SetInternalBorder(framePtr->tkwin,
  555.         framePtr->borderWidth + framePtr->highlightWidth);
  556.     if ((framePtr->width > 0) || (framePtr->height > 0)) {
  557.     Tk_GeometryRequest(framePtr->tkwin, framePtr->width,
  558.         framePtr->height);
  559.     }
  560.  
  561.     if (Tk_IsMapped(framePtr->tkwin)) {
  562.     if (!(framePtr->flags & REDRAW_PENDING)) {
  563.         Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  564.     }
  565.     framePtr->flags |= REDRAW_PENDING|CLEAR_NEEDED;
  566.     }
  567.     return TCL_OK;
  568. }
  569.  
  570. /*
  571.  *----------------------------------------------------------------------
  572.  *
  573.  * DisplayFrame --
  574.  *
  575.  *    This procedure is invoked to display a frame widget.
  576.  *
  577.  * Results:
  578.  *    None.
  579.  *
  580.  * Side effects:
  581.  *    Commands are output to X to display the frame in its
  582.  *    current mode.
  583.  *
  584.  *----------------------------------------------------------------------
  585.  */
  586.  
  587. static void
  588. DisplayFrame(clientData)
  589.     ClientData clientData;    /* Information about widget. */
  590. {
  591.     register Frame *framePtr = (Frame *) clientData;
  592.     register Tk_Window tkwin = framePtr->tkwin;
  593.     GC gc;
  594.  
  595.     framePtr->flags &= ~REDRAW_PENDING;
  596.     if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  597.     return;
  598.     }
  599.  
  600.     if (framePtr->flags & CLEAR_NEEDED) {
  601.     XClearWindow(framePtr->display, Tk_WindowId(tkwin));
  602.     framePtr->flags &= ~CLEAR_NEEDED;
  603.     }
  604.     if ((framePtr->border != NULL)
  605.         && (framePtr->relief != TK_RELIEF_FLAT)) {
  606.     Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
  607.         framePtr->border, framePtr->highlightWidth,
  608.         framePtr->highlightWidth,
  609.         Tk_Width(tkwin) - 2*framePtr->highlightWidth,
  610.         Tk_Height(tkwin) - 2*framePtr->highlightWidth,
  611.         framePtr->borderWidth, framePtr->relief);
  612.     }
  613.     if (framePtr->highlightWidth != 0) {
  614.     if (framePtr->flags & GOT_FOCUS) {
  615.         gc = Tk_GCForColor(framePtr->highlightColorPtr,
  616.             Tk_WindowId(tkwin));
  617.     } else {
  618.         gc = Tk_GCForColor(framePtr->highlightBgColorPtr,
  619.             Tk_WindowId(tkwin));
  620.     }
  621.     Tk_DrawFocusHighlight(tkwin, gc, framePtr->highlightWidth,
  622.         Tk_WindowId(tkwin));
  623.     }
  624. }
  625.  
  626. /*
  627.  *--------------------------------------------------------------
  628.  *
  629.  * FrameEventProc --
  630.  *
  631.  *    This procedure is invoked by the Tk dispatcher on
  632.  *    structure changes to a frame.  For frames with 3D
  633.  *    borders, this procedure is also invoked for exposures.
  634.  *
  635.  * Results:
  636.  *    None.
  637.  *
  638.  * Side effects:
  639.  *    When the window gets deleted, internal structures get
  640.  *    cleaned up.  When it gets exposed, it is redisplayed.
  641.  *
  642.  *--------------------------------------------------------------
  643.  */
  644.  
  645. static void
  646. FrameEventProc(clientData, eventPtr)
  647.     ClientData clientData;    /* Information about window. */
  648.     register XEvent *eventPtr;    /* Information about event. */
  649. {
  650.     register Frame *framePtr = (Frame *) clientData;
  651.  
  652.     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
  653.     goto redraw;
  654.     } else if (eventPtr->type == ConfigureNotify) {
  655.     /*
  656.      * If the window changed size then the borders need to be
  657.      * redrawn.
  658.      */
  659.  
  660.     framePtr->flags |= CLEAR_NEEDED;
  661.     goto redraw;
  662.     } else if (eventPtr->type == DestroyNotify) {
  663.     if (framePtr->tkwin != NULL) {
  664.         framePtr->tkwin = NULL;
  665.         Tcl_DeleteCommand(framePtr->interp,
  666.             Tcl_GetCommandName(framePtr->interp, framePtr->widgetCmd));
  667.     }
  668.     if (framePtr->flags & REDRAW_PENDING) {
  669.         Tk_CancelIdleCall(DisplayFrame, (ClientData) framePtr);
  670.     }
  671.     Tk_CancelIdleCall(MapFrame, (ClientData) framePtr);
  672.     Tk_EventuallyFree((ClientData) framePtr, DestroyFrame);
  673.     } else if (eventPtr->type == FocusIn) {
  674.     if (eventPtr->xfocus.detail != NotifyInferior) {
  675.         framePtr->flags |= GOT_FOCUS;
  676.         if (framePtr->highlightWidth > 0) {
  677.         goto redraw;
  678.         }
  679.     }
  680.     } else if (eventPtr->type == FocusOut) {
  681.     if (eventPtr->xfocus.detail != NotifyInferior) {
  682.         framePtr->flags &= ~GOT_FOCUS;
  683.         if (framePtr->highlightWidth > 0) {
  684.         goto redraw;
  685.         }
  686.     }
  687.     }
  688.     return;
  689.  
  690.     redraw:
  691.     if ((framePtr->tkwin != NULL) && !(framePtr->flags & REDRAW_PENDING)) {
  692.     Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  693.     framePtr->flags |= REDRAW_PENDING;
  694.     }
  695. }
  696.  
  697. /*
  698.  *----------------------------------------------------------------------
  699.  *
  700.  * FrameCmdDeletedProc --
  701.  *
  702.  *    This procedure is invoked when a widget command is deleted.  If
  703.  *    the widget isn't already in the process of being destroyed,
  704.  *    this command destroys it.
  705.  *
  706.  * Results:
  707.  *    None.
  708.  *
  709.  * Side effects:
  710.  *    The widget is destroyed.
  711.  *
  712.  *----------------------------------------------------------------------
  713.  */
  714.  
  715. static void
  716. FrameCmdDeletedProc(clientData)
  717.     ClientData clientData;    /* Pointer to widget record for widget. */
  718. {
  719.     Frame *framePtr = (Frame *) clientData;
  720.     Tk_Window tkwin = framePtr->tkwin;
  721.  
  722.     /*
  723.      * This procedure could be invoked either because the window was
  724.      * destroyed and the command was then deleted (in which case tkwin
  725.      * is NULL) or because the command was deleted, and then this procedure
  726.      * destroys the widget.
  727.      */
  728.  
  729.     if (tkwin != NULL) {
  730.     framePtr->tkwin = NULL;
  731.     Tk_DestroyWindow(tkwin);
  732.     }
  733. }
  734.  
  735. /*
  736.  *----------------------------------------------------------------------
  737.  *
  738.  * MapFrame --
  739.  *
  740.  *    This procedure is invoked as a when-idle handler to map a
  741.  *    newly-created top-level frame.
  742.  *
  743.  * Results:
  744.  *    None.
  745.  *
  746.  * Side effects:
  747.  *    The frame given by the clientData argument is mapped.
  748.  *
  749.  *----------------------------------------------------------------------
  750.  */
  751.  
  752. static void
  753. MapFrame(clientData)
  754.     ClientData clientData;        /* Pointer to frame structure. */
  755. {
  756.     Frame *framePtr = (Frame *) clientData;
  757.  
  758.     /*
  759.      * Wait for all other background events to be processed before
  760.      * mapping window.  This ensures that the window's correct geometry
  761.      * will have been determined before it is first mapped, so that the
  762.      * window manager doesn't get a false idea of its desired geometry.
  763.      */
  764.  
  765.     Tk_Preserve((ClientData) framePtr);
  766.     while (1) {
  767.     if (Tk_DoOneEvent(TK_IDLE_EVENTS) == 0) {
  768.         break;
  769.     }
  770.  
  771.     /*
  772.      * After each event, make sure that the window still exists
  773.      * and quit if the window has been destroyed.
  774.      */
  775.  
  776.     if (framePtr->tkwin == NULL) {
  777.         Tk_Release((ClientData) framePtr);
  778.         return;
  779.     }
  780.     }
  781.     Tk_MapWindow(framePtr->tkwin);
  782.     Tk_Release((ClientData) framePtr);
  783. }
  784.